#include "mysql_conn_pool.hpp"
#include <muduo/base/Logging.h>

mysql_connPool* mysql_connPool::getInstance(){
    static mysql_connPool m_instance;
    return &m_instance;
}

mysql_connPool::mysql_connPool(){
    
}

mysql_connPool::~mysql_connPool(){
    if(max_conn>0){
        sem_destroy(&m_sem);
        this->destory_pool();
    }
}

//初始化数据库连接池(需主动调用一次)
bool mysql_connPool::init(string url,string user,string password,string database,int port,int maxConn){
    this->m_url=url;
    this->m_user=user;
    this->m_password=password;
    this->m_database=database;
    this->m_port=port;
    this->max_conn=maxConn;
    

    //如果最大连接为0则设置相关参数并直接返回
    if(maxConn<=0){
        this->cur_conn=0;
        this->free_conn=0;
        return false;
    }

    MySQL* temp=nullptr;
    //否则根据最大的连接数来初始化连接池
    for(int i=0;i<max_conn;++i){
        temp=new MySQL;
        bool res=temp->init(m_url,m_user,m_password,m_port,m_database);
        if(res==false){
            LOG_ERROR<<"数据库连接初始化失败！";
            return false;
        }

        m_pool.push(temp);
        ++this->free_conn;
    }
    
    //信号量初始化为最大连接数目
    if(sem_init(&m_sem,0,maxConn)!=0){
        LOG_ERROR<<"连接池信号量初始化错误！";
        return false;
    }

    this->cur_conn=0;
    this->max_conn=free_conn;
    
    //!debug
    LOG_INFO<<"create sql conn pool ok! pool size: "<<maxConn<<"  ";
    return true;
}


//销毁连接池
void mysql_connPool::destory_pool(){
    m_lock.lock();
    while(!m_pool.empty()){
        //队列不为空则一直拿出连接进行销毁
        MySQL* temp_sql=m_pool.front();
        m_pool.pop();
        delete temp_sql;
        temp_sql=nullptr;
    }

    this->max_conn=0;
    this->cur_conn=0;
    this->free_conn=0;
    LOG_INFO<<"destroy pool ok!";
    m_lock.unlock();
}

//从连接池中获取一个连接
MySQL* mysql_connPool::get_conn(){
    MySQL* conn=nullptr;

    if(this->max_conn==0){
        conn;
    }

    //等待连接池信号量
    sem_wait(&m_sem);
    //获取连接，加锁
    m_lock.lock();
    
    conn=m_pool.front();
    m_pool.pop();
    --free_conn;
    ++cur_conn;

    m_lock.unlock();
    return conn;

}

//释放一个连接，将其放回连接池
bool mysql_connPool::release_conn(MySQL* conn){
    if(conn==nullptr)
        return false;//别给我空的指针啊

    m_lock.lock();

    m_pool.push(conn);
    ++free_conn;
    --cur_conn;
    sem_post(&m_sem);

    m_lock.unlock();

    return true;
}

mysql_connpool_RAII::mysql_connpool_RAII(MySQL** conn,mysql_connPool* connPool){
    *conn=connPool->get_conn();

    this->m_connRAII=*conn;
    this->connPool=connPool;
}

mysql_connpool_RAII::~mysql_connpool_RAII(){
    this->connPool->getInstance()->release_conn(this->m_connRAII);
}